/**
 ** 数据存储器
**/

module dataMemory (
    input wire clk,             //时钟信号
    input wire [31:0] now_inst, //当前的指令内容     
    input [2:0] dm_rd_ctrl,   //数据读取控制信号
    input [1:0] dm_wr_ctrl,   //数据写入控制信号
    input [31:0] dm_addr,     //读or写地址
    input [31:0] dm_din,      //待写入的内容
    output reg [31:0] dm_dout,//存储器的输出
    output reg [31:0] dm_inst_out,
    output reg [31:0] dm_exe_result_out
);
    //定义数组模拟存储器
    reg [3:0] byte_en;
    reg [31:0] mem[0:4095];
    reg [31:0] mem_out;
    integer i;

    initial begin
        //初始化存储单元
        for (i = 0; i < 4096; i++) begin
            mem[i] = 0;
        end
    end

    //由于不能跨单位读取数据，地址最低两位的数值决定了当前单位能读取到的数据，即mem_out
    always @(*) begin
        case (dm_addr[1:0])
            2'b00: mem_out = mem[dm_addr[13:2]][31:0];
            2'b01: mem_out = {8'h0,mem[dm_addr[13:2]][31:8]};
            2'b10: mem_out = {16'h0,mem[dm_addr[13:2]][31:16]};
            2'b11: mem_out = {24'h0,mem[dm_addr[13:2]][31:24]};
        endcase
        //把指令传出去
        dm_inst_out = now_inst;
        dm_exe_result_out = dm_addr;
    end

    //对读取内容进行对应的拓展
    always @(*) begin
        case(dm_rd_ctrl)     
            3'b001: dm_dout = {{24{mem_out[7]}}, mem_out[7:0]}; 
            3'b010: dm_dout = {{24{1'b0}}, mem_out[7:0]}; 
            3'b011: dm_dout = {{16{mem_out[15]}}, mem_out[15:0]}; 
            3'b100: dm_dout = {{16{1'b0}}, mem_out[15:0]}; 
            3'b101: dm_dout = mem_out[31:0];
            default: dm_dout = 0;
        endcase
    end

    //实际上，使用byte_en标记实际上要写入的字节是哪些
    always @(*) begin
        if(dm_wr_ctrl == 2'b11)
            byte_en = 4'b1111;
        else if(dm_wr_ctrl == 2'b10) begin
            if(dm_addr[1] == 1'b1) 
                byte_en = 4'b1100;
            else
                byte_en = 4'b0011;
        end
        else if(dm_wr_ctrl == 2'b01) begin
            case(dm_addr[1:0])
            2'b00:  byte_en = 4'b0001;
            2'b01:  byte_en = 4'b0010;
            2'b10:  byte_en = 4'b0100;
            2'b11:  byte_en = 4'b1000;
            endcase
        end
        else
            byte_en = 4'b0000;
    end

    //借助辅助变量，将数据写入到指定的位置
    always @(posedge clk) begin
        
        if((byte_en != 1'b0)&&(dm_addr[30:12]==19'b0)) begin
            case(byte_en)
                4'b0001: mem[dm_addr[13:2]][7:0] = dm_din[7:0]; //单字节写入
                4'b0010: mem[dm_addr[13:2]][15:8] = dm_din[7:0]; //单字节写入
                4'b0100: mem[dm_addr[13:2]][23:16] = dm_din[7:0]; //单字节写入
                4'b1000: mem[dm_addr[13:2]][31:24] = dm_din[7:0]; //单字节写入
                4'b0011: mem[dm_addr[13:2]][15:0] = dm_din[15:0]; //半字写入
                4'b1100: mem[dm_addr[13:2]][31:16] = dm_din[15:0]; //半字写入
                4'b1111: mem[dm_addr[13:2]] = dm_din[31:0]; //整字写入
                default: mem[dm_addr[13:2]] = 0;
            endcase
        end
    end
endmodule